package com.hospital.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hospital.dto.DoctorPageQueryDTO;
import com.hospital.entity.*;
import com.hospital.enumeration.BusinessExceptionEnum;
import com.hospital.exception.BusinessException;
import com.hospital.mapper.*;
import com.hospital.result.PageResult;
import com.hospital.service.DoctorService;
import com.hospital.service.util.DoctorCheckUtil;
import com.hospital.service.util.PatientCheckUtil;
import com.hospital.vo.DoctorInfoVO;
import com.hospital.vo.DoctorListVO;
import com.hospital.vo.PatientListVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DoctorServiceImpl extends ServiceImpl<DoctorMapper, Doctor> implements DoctorService {
    @Autowired
    private DoctorMapper doctorMapper;
    @Autowired
    private DepartmentMapper departmentMapper;
    @Autowired
    private PatientMapper patientMapper;
    @Autowired
    private TreatmentRecordMapper treatmentRecordMapper;
    @Autowired
    private WardMapper wardMapper;
    @Autowired
    private HospitalizationRecordMapper hospitalizationRecordMapper;

    @Autowired
    private DoctorCheckUtil doctorCheckUtil;
    @Autowired
    private PatientCheckUtil patientCheckUtil;

    @Override
    public Long assignDoctor(Long deptId) {
        // 1. 找到该科室的医生，判断该医生是否有空闲的病人
        Doctor doctor = doctorMapper.selectOne(
                new LambdaQueryWrapper<Doctor>()
                        .eq(Doctor::getDeptId, deptId)
                        .apply("current_patient_count < max_patient_count")
                        .last("ORDER BY RAND() LIMIT 1")
        );

        // 2. 如果没有空闲的医生，抛出异常
        if (doctor == null) {
            throw new BusinessException(BusinessExceptionEnum.NO_DOCTOR_AVAILABLE_IN_DEPT);
        }

        // 3.重置该医生的病人数
        doctor.setCurrentPatientCount(doctor.getCurrentPatientCount() + 1);
        doctorMapper.updateById(doctor);

        // 4. 返回该医生的id
        return doctor.getDoctorId();
    }

    @Override
    public PageResult getDoctorList(DoctorPageQueryDTO doctorPageQueryDTO) {
        IPage<DoctorListVO> page = new Page<>(doctorPageQueryDTO.getPageNumber(), doctorPageQueryDTO.getPageSize());

        doctorMapper.pageQuery(page, doctorPageQueryDTO.getName());

        return PageResult.builder()
                .total(page.getTotal())
                .records(page.getRecords())
                .build();
    }

    @Override
    public DoctorInfoVO getDoctorInfo(Long doctorId) {
        DoctorInfoVO doctorInfoVO = new DoctorInfoVO();
        Doctor doctor = doctorMapper.selectById(doctorId);

        // 校验医生是否存在
        doctorCheckUtil.checkDoctor(doctor);

        BeanUtils.copyProperties(doctor, doctorInfoVO);

        log.info("doctor: {}", doctor);
        log.info("doctorInfoVO: {}", doctorInfoVO);

        Department department = departmentMapper.selectById(doctor.getDeptId());
        doctorInfoVO.setDeptName(department.getDeptName());

        // 完善病人信息
        List<PatientListVO> patients = treatmentRecordMapper.selectList(
                new LambdaQueryWrapper<TreatmentRecord>()
                        .eq(TreatmentRecord::getDoctorId, doctorId)
        ).stream().map(TreatmentRecord::getPatientId).map(patientId -> {
            Patient patient = patientMapper.selectById(patientId);

            HospitalizationRecord hospitalizationRecord = hospitalizationRecordMapper.selectOne(
                    new LambdaQueryWrapper<HospitalizationRecord>()
                            .eq(HospitalizationRecord::getPatientId, patientId)
            );
            if (hospitalizationRecord.getDischargeTime() != null) return null;

            Ward ward = wardMapper.selectById(hospitalizationRecord.getWardId());
            return PatientListVO.builder()
                    .patientId(patient.getPatientId())
                    .name(patient.getName())
                    .gender(patient.getGender())
                    .deptName(department.getDeptName())
                    .location(ward.getLocation())
                    .build();
        }).filter(Objects::nonNull).collect(Collectors.toList());
        doctorInfoVO.setPatients(patients);

        return doctorInfoVO;
    }
}
